package org.smartbird
{
	import com.adobe.serialization.json.JSON;
	
	import flash.events.*;
	import flash.net.Socket;
    
	public class SmartBirdClient extends Socket
	{
		private var _userManager:UserManager;
		private var _roomManager:RoomManager;
        private var extObj:Object;
        private var mySelfUserId:int;

        public function SmartBirdClient() 
        {
        	this._userManager = new UserManager();
        	this._roomManager = new RoomManager();
            addEventListener(Event.CONNECT, connectHandler);
            addEventListener(Event.CLOSE, closeHandler);
            addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
            addEventListener(ProgressEvent.PROGRESS, progressHandler);
            addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
            addEventListener(ProgressEvent.SOCKET_DATA, dataHandler);
        }
        
        public function get userManager():UserManager
        {
        	return _userManager;
        }
        
        public function get roomManager():RoomManager
        {
        	return _roomManager;
        }
        
        public function setExtension(extObj:Object):void
        {
        	this.extObj = extObj;
        }
        
        public function sendUpStreamDataObject(upDo:UpStreamDataObject):void
        {
        	send(JSON.encode(upDo) + "\r\n");
        }
        
        public function get mySelf():User
        {
        	return userManager.getUserById(mySelfUserId);
        }
        
        public function login(id:int):void
        {
        	var upDo:UpStreamDataObject = new UpStreamDataObject();
        	upDo.method = "login";
        	upDo.data.id = id; 
            sendUpStreamDataObject(upDo);
        }

        public function send(data:String):void 
        {
        	trace("send", data);
        	if (this.connected)
        	{
            	this.writeUTFBytes(data);
            	this.flush();
         	}
        }

        protected function closeHandler(event:Event):void {
            trace("closeHandler: " + event);
        }
        
        public function sendMessage(message:String, type:int):void
        {
        	var upDo:UpStreamDataObject = new UpStreamDataObject();
        	var msg:Message = new Message();
        	msg.message = message;
        	msg.type = type;
        	upDo.method = "sendMessage";
        	upDo.data = msg;
        	sendUpStreamDataObject(upDo);
        }
        
        private function onRoomVariablesUpdateSBS(jsonObj:Object):void
        {
        	var room:Room = roomManager.getRoomById(jsonObj.data.roomId);
        	if (room != null)
        	{
        		var varToUpdate:Object = jsonObj.data.variables;
        		for (var varName:String in varToUpdate)
        		{
        			room.roomVariables[varName] = varToUpdate[varName];
        		}
		    	var event:SBSEvent = new SBSEvent(SBSEvent.ROOM_VARIABLES_UPDATE);
		    	event.params.room = room;
		    	event.params.variables = varToUpdate;
		    	dispatchEvent(event);
        	}
        }

        private function onUserVariablesUpdateSBS(jsonObj:Object):void
        {
        	var user:User = userManager.getUserById(jsonObj.data.userId);
        	if (user != null)
        	{
        		var varToUpdate:Object = jsonObj.data.variables;
        		for (var varName:String in varToUpdate)
        		{
        			user.userVariables[varName] = varToUpdate[varName];
        		}
		    	var event:SBSEvent = new SBSEvent(SBSEvent.USER_VARIABLES_UPDATE);
		    	event.params.user = user;
		    	event.params.variables = varToUpdate;
		    	dispatchEvent(event);
        	}
        }
        
        private function onUserEnterRoomSBS(jsonObj:Object):void
        {
        	var roomId:int = jsonObj.roomId;
        	var room:Room = roomManager.getRoomById(roomId);
        	if (room != null)
        	{
	        	var user:User = new User(this);
	        	user.loadbyObject(jsonObj.data.user);
	        	userManager.addUser(user);
	        	room.addUser(user);
		    	var event:SBSEvent = new SBSEvent(SBSEvent.USER_ENTER_ROOM);
		    	event.params.user = user;
		    	event.params.room = room;
		    	dispatchEvent(event);
        	}
        }

        private function onUserExitRoomSBS(jsonObj:Object):void
        {
        	var roomId:int = jsonObj.roomId;
        	var room:Room = roomManager.getRoomById(roomId);
        	if (room != null)
        	{
	        	var user:User = new User(this);
	        	user.loadbyObject(jsonObj.data.user);
	        	room.removeUser(user);
		    	var event:SBSEvent = new SBSEvent(SBSEvent.USER_EXIT_ROOM);
		    	event.params.user = user;
		    	event.params.room = room;
		    	dispatchEvent(event);
        	}
        }

        private function onJoinRoomSBS(jsonObj:Object):void
        {
			var room:Room = new Room(this);
			room.loadbyObject(jsonObj.data.room);
			roomManager.addRoom(room);
			mySelf.currentRoomId = room.id;
			var userList:Object = jsonObj.data.userList;
			for (var userIdStr:String in userList)
			{
				var user:User = new User(this);
				user.loadbyObject(userList[userIdStr]);
				userManager.addUser(user);
				room.addUser(user);
			}
        	var event:SBSEvent = new SBSEvent(SBSEvent.ROOM_JOIN);
        	event.params.room = room;
        	dispatchEvent(event);
        }
        
        private function onLoginSBS(jsonObj:Object):void
        {
        	var user:User = new User(this);
        	user.loadbyObject(jsonObj.data.user);
        	userManager.addUser(user);
        	mySelfUserId = user.id;
        	dispatchEvent(new SBSEvent(SBSEvent.LOGIN));
        }
        
        protected function dataHandler(event:ProgressEvent):void {
        	var incoming:String = this.readUTFBytes(this.bytesAvailable);
        	trace("dataHandler", incoming);
        	var commands:Array = incoming.split("\r\n");
        	for (var i:int = 0; i < commands.length; i++)
        	{
	        	try
	        	{
	            	var jsonObj:Object = JSON.decode(commands[i]);
					if (extObj != null && extObj.hasOwnProperty(jsonObj.method))
					{
		            	var method:Function = extObj[jsonObj.method];
						method.apply(this, [jsonObj]);
					}
					else
					{
		            	method = this[jsonObj.method];
						method.apply(this, [jsonObj]);
					}
        		}
				catch (e:Error)
				{
					trace(e.message);	
				}
        	}
        }

        protected function connectHandler(event:Event):void {
        	dispatchEvent(new SBSEvent(SBSEvent.CONNECTION));
        }

        protected function ioErrorHandler(event:IOErrorEvent):void {
            trace("ioErrorHandler: " + event);
        }

        protected function progressHandler(event:ProgressEvent):void {
            trace("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal);
        }

        protected function securityErrorHandler(event:SecurityErrorEvent):void {
            trace("securityErrorHandler: " + event);
        }

	}
}